1 using System.Collections.Generic;
2 using
System.Diagnostics;
3 using
System.IO;
4 using
UnityEditor;
5 using
UnityEngine;
6 using
System.Collections;
7 using
Debug = UnityEngine.Debug;
8
9 [InitializeOnLoad]

10 public
class PhotonViewHandler : EditorWindow
11 {
12     
private static bool CheckSceneForStuckHandlers = true;
13
14     
static PhotonViewHandler()
15     {
16         
// hierarchyWindowChanged is called on hierarchy changed and on save. It's even called when hierarchy-window is closed and if a prefab with instances is changed.
17         
// this is not called when you edit a instance's value but: on save
18         EditorApplication.hierarchyWindowChanged += HierarchyChange;
19     }
20
21     
// this method corrects the IDs for photonviews in the scene and in prefabs
22     
// make sure prefabs always use viewID 0
23     
// make sure instances never use a owner
24     
// this is a editor class that should only run if not playing
25     
internal static void HierarchyChange()
26     {
27         
if (Application.isPlaying)
28         {
29             
//Debug.Log("HierarchyChange ignored, while running.");
30             CheckSceneForStuckHandlers =
true; // done once AFTER play mode.
31             
return;
32         }
33
34         
if (CheckSceneForStuckHandlers)
35         {
36             CheckSceneForStuckHandlers =
false;
37             PhotonNetwork.InternalCleanPhotonMonoFromSceneIfStuck();
38         }
39
40         HashSet<PhotonView> pvInstances =
new HashSet<PhotonView>();
41         HashSet<
int> usedInstanceViewNumbers = new HashSet<int>();
42         
bool fixedSomeId = false;
43
44         ///
/ the following code would be an option if we only checked scene objects (but we can check all PVs)
45         
//PhotonView[] pvObjects = GameObject.FindSceneObjectsOfType(typeof(PhotonView)) as PhotonView[];
46         
//Debug.Log("HierarchyChange. PV Count: " + pvObjects.Length);
47
48         
string levelName = Application.loadedLevelName;
49         #
if UNITY_EDITOR
50         levelName = System.IO.Path.GetFileNameWithoutExtension(EditorApplication.currentScene);
51         #endif
52         
int minViewIdInThisScene = PunSceneSettings.MinViewIdForScene(levelName);
53         
//Debug.Log("Level '" + Application.loadedLevelName + "' has a minimum ViewId of: " + minViewIdInThisScene);
54
55         PhotonView[] pvObjects = Resources.FindObjectsOfTypeAll(
typeof(PhotonView)) as PhotonView[];
56
57         
foreach (PhotonView view in pvObjects)
58         {
59             
// first pass: fix prefabs to viewID 0 if they got a view number assigned (cause they should not have one!)
60             
if (EditorUtility.IsPersistent(view.gameObject))
61             {
62                 
if (view.viewID != 0 || view.prefixBackup != -1 || view.instantiationId != -1)
63                 {
64                     Debug.LogWarning(
"PhotonView on persistent object being fixed (id and prefix must be 0). Was: " + view);
65                     view.viewID =
0;
66                     view.prefixBackup = -
1;
67                     view.instantiationId = -
1;
68                     EditorUtility.SetDirty(view);
69                     fixedSomeId =
true;
70                 }
71             }
72             
else
73             {
74                 
// keep all scene-instanced PVs for later re-check
75                 pvInstances.Add(view);
76             }
77         }
78
79         Dictionary<GameObject,
int> idPerObject = new Dictionary<GameObject, int>();
80
81         
// second pass: check all used-in-scene viewIDs for duplicate viewIDs (only checking anything non-prefab)
82         
// scene-PVs must have user == 0 (scene/room) and a subId != 0
83         
foreach (PhotonView view in pvInstances)
84         {
85             
if (view.ownerId > 0)
86             {
87                 Debug.Log(
"Re-Setting Owner ID of: " + view);
88             }
89             view.ownerId =
0; // simply make sure no owner is set (cause room always uses 0)
90             view.prefix = -
1; // TODO: prefix could be settable via inspector per scene?!
91
92             
if (view.viewID != 0)
93             {
94                 
if (view.viewID < minViewIdInThisScene || usedInstanceViewNumbers.Contains(view.viewID))
95                 {
96                     view.viewID =
0; // avoid duplicates and negative values by assigning 0 as (temporary) number to be fixed in next pass
97                 }
98                 
else
99                 {
100                     usedInstanceViewNumbers.Add(view.viewID);
// builds a list of currently used viewIDs
101
102                     
int instId = 0;
103                     
if (idPerObject.TryGetValue(view.gameObject, out instId))
104                     {
105                         view.instantiationId = instId;
106                     }
107                     
else
108                     {
109                         view.instantiationId = view.viewID;
110                         idPerObject[view.gameObject] = view.instantiationId;
111                     }
112                 }
113             }
114
115         }
116
117         
// third pass: anything that's now 0 must get a new (not yet used) ID (starting at 0)
118         
int lastUsedId = (minViewIdInThisScene > 0) ? minViewIdInThisScene - 1 : 0;
119
120         
foreach (PhotonView view in pvInstances)
121         {
122             
if (view.viewID == 0)
123             {
124                 
// Debug.LogWarning("setting scene ID: " + view.gameObject.name + " ID: " + view.subId.ID + " scene ID: " + view.GetSceneID() + " IsPersistent: " + EditorUtility.IsPersistent(view.gameObject) + " IsSceneViewIDFree: " + IsSceneViewIDFree(view.subId.ID, view));
125                 
int nextViewId = PhotonViewHandler.GetID(lastUsedId, usedInstanceViewNumbers);
126
127                 view.viewID = nextViewId;
128
129                 
int instId = 0;
130                 
if (idPerObject.TryGetValue(view.gameObject, out instId))
131                 {
132                     Debug.Log(
"Set inst ID");
133                     view.instantiationId = instId;
134                 }
135                 
else
136                 {
137                     view.instantiationId = view.viewID;
138                     idPerObject[view.gameObject] = nextViewId;
139                 }

140
141                 ///
/ when using the Editor's serialization (view.subId in this case), this is not needed, it seems
142                 
//PrefabUtility.RecordPrefabInstancePropertyModifications(view);
143
144                 lastUsedId = nextViewId;
145                 EditorUtility.SetDirty(view);
146                 fixedSomeId =
true;
147             }
148         }
149         
150
151         
if (fixedSomeId)
152         {
153             
//Debug.LogWarning("Some subId was adjusted."); // this log is only interesting for Exit Games
154         }
155     }
156
157     
// TODO fail if no ID was available anymore
158     
// TODO look up lower numbers if offset hits max?!
159     
public static int GetID(int idOffset, HashSet<int> usedInstanceViewNumbers)
160     {
161         
while (idOffset < PhotonNetwork.MAX_VIEW_IDS)
162         {
163             idOffset++;
164             
if (!usedInstanceViewNumbers.Contains(idOffset))
165             {
166                 
break;
167             }
168         }
169
170         
return idOffset;
171     }
172
173     
//TODO: check if this can be internal protected (as source in editor AND as dll)
174     
public static void LoadAllScenesToFix()
175     {
176         
string[] scenes = System.IO.Directory.GetFiles(".", "*.unity", SearchOption.AllDirectories);
177
178         
foreach (string scene in scenes)
179         {
180             EditorApplication.OpenScene(scene);
181
182             PhotonViewHandler.HierarchyChange();
//TODO: most likely on load also triggers a hierarchy change
183
184             EditorApplication.SaveScene();
185         }
186
187         Debug.Log(
"Corrected scene views where needed.");
188     }
189 }


hierarchyWindowChanged is called on hierarchy changed and on save. It's even called when hierarchy-window is closed and if a prefab with instances is changed.

this is not called when you edit a instance's value but: on save

this method corrects the IDs for photonviews in the scene and in prefabs

make sure prefabs always use viewID 0

make sure instances never use a owner

this is a editor class that should only run if not playing

Debug.Log("HierarchyChange ignored, while running.");

CheckSceneForStuckHandlers = true; done once AFTER play mode.

the following code would be an option if we only checked scene objects (but we can check all PVs)

PhotonView[] pvObjects = GameObject.FindSceneObjectsOfType(typeof(PhotonView)) as PhotonView[];

Debug.Log("HierarchyChange. PV Count: " + pvObjects.Length);

Debug.Log("Level '" + Application.loadedLevelName + "' has a minimum ViewId of: " + minViewIdInThisScene);

first pass: fix prefabs to viewID 0 if they got a view number assigned (cause they should not have one!)

keep all scene-instanced PVs for later re-check

second pass: check all used-in-scene viewIDs for duplicate viewIDs (only checking anything non-prefab)

scene-PVs must have user == 0 (sceneroom) and a subId != 0

view.ownerId = 0; simply make sure no owner is set (cause room always uses 0)

view.prefix = -1; TODO: prefix could be settable via inspector per scene?!

view.viewID = 0; avoid duplicates and negative values by assigning 0 as (temporary) number to be fixed in next pass

usedInstanceViewNumbers.Add(view.viewID); builds a list of currently used viewIDs

third pass: anything that's now 0 must get a new (not yet used) ID (starting at 0)

Debug.LogWarning("setting scene ID: " + view.gameObject.name + " ID: " + view.subId.ID + " scene ID: " + view.GetSceneID() + " IsPersistent: " + EditorUtility.IsPersistent(view.gameObject) + " IsSceneViewIDFree: " + IsSceneViewIDFree(view.subId.ID, view));

when using the Editor's serialization (view.subId in this case), this is not needed, it seems

PrefabUtility.RecordPrefabInstancePropertyModifications(view);

Debug.LogWarning("Some subId was adjusted."); this log is only interesting for Exit Games

TODO fail if no ID was available anymore

TODO look up lower numbers if offset hits max?!

TODO: check if this can be internal protected (as source in editor AND as dll)

PhotonViewHandler.HierarchyChange();TODO: most likely on load also triggers a hierarchy change




Trò chơi Tic-Tac-Toe, game đánh caro full source code 53.432 lượt xem

Gõ tìm kiếm nhanh...